package com.socio.activities;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.socio.model.ClientUser;
import com.socio.threads.BackendThread;
import com.socio.threads.BackendThread.BackendThreadMessages;
import com.socio.threads.BackendThread.BackendThreadModes;
import com.socio.utils.SocioUtils;

public class SocioLauncher extends Activity {
	
	// different types of dialogs
	static final int SEARCH_PROGRESS_DIALOG = 0;
	static final int TROUBLE_GETTING_LEADERBOARD = 1;
	static final int NO_DATA_FOUND = 2;
	static final int N0_SCORING_DIALOG = 3;
	
	// view components
	private TextView graphDate;
	private LinearLayout bar1;
	private LinearLayout bar2;
	private LinearLayout bar3;
	private LinearLayout bar4;
	private LinearLayout barMask1;
	private LinearLayout barMask2;
	private LinearLayout barMask3;
	private LinearLayout barMask4;
	private TextView barTitleNickname1;
	private TextView barTitleNickname2;
	private TextView barTitleNickname3;
	private TextView barTitleNickname4;
	private TextView barTitlePoints1;
	private TextView barTitlePoints2;
	private TextView barTitlePoints3;
	private TextView barTitlePoints4;
	private LinearLayout barTitleTopMargin1;
	private LinearLayout barTitleTopMargin2;
	private LinearLayout barTitleTopMargin3;
	private LinearLayout barTitleTopMargin4;
	private Button previousButton;
	private Button todayButton;
	private Button nextButton;
	private RelativeLayout barDisplay1;
	private RelativeLayout barDisplay2;
	private RelativeLayout barDisplay3;
	private RelativeLayout barDisplay4;
	private LinearLayout noData;
	
	private TelephonyManager telephonyManager;
	
	private long displayDateTime;
	private List<ClientUser> displayList;
	
	// Define the Handler that receives messages from the search thread and update the progress
    final Handler handler = new Handler() { public void handleMessage(Message msg) { handleBackendThreadMessage(msg);}};
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.graph);
        setTitle(R.string.socio_launcher_activity_title);
        
        // get components
        graphDate = (TextView)findViewById(R.id.GraphDate);
        barTitleNickname1 = (TextView)findViewById(R.id.BarTitleNickname1);
        barTitleNickname2 = (TextView)findViewById(R.id.BarTitleNickname2);
        barTitleNickname3 = (TextView)findViewById(R.id.BarTitleNickname3);
        barTitleNickname4 = (TextView)findViewById(R.id.BarTitleNickname4);
        barTitlePoints1 = (TextView)findViewById(R.id.BarTitlePoints1);
        barTitlePoints2 = (TextView)findViewById(R.id.BarTitlePoints2);
        barTitlePoints3 = (TextView)findViewById(R.id.BarTitlePoints3);
        barTitlePoints4 = (TextView)findViewById(R.id.BarTitlePoints4);
        bar1 = (LinearLayout)findViewById(R.id.Bar1);
        bar2 = (LinearLayout)findViewById(R.id.Bar2);
        bar3 = (LinearLayout)findViewById(R.id.Bar3);
        bar4 = (LinearLayout)findViewById(R.id.Bar4);
        barMask1 = (LinearLayout)findViewById(R.id.BarMask1);
        barMask2 = (LinearLayout)findViewById(R.id.BarMask2);
        barMask3 = (LinearLayout)findViewById(R.id.BarMask3);
        barMask4 = (LinearLayout)findViewById(R.id.BarMask4);
        barDisplay1 = (RelativeLayout)findViewById(R.id.BarDisplayLayout1);
        barDisplay2 = (RelativeLayout)findViewById(R.id.BarDisplayLayout2);
        barDisplay3 = (RelativeLayout)findViewById(R.id.BarDisplayLayout3);
        barDisplay4 = (RelativeLayout)findViewById(R.id.BarDisplayLayout4);
        barTitleTopMargin1 = (LinearLayout)findViewById(R.id.BarTitleTopMargin1);
        barTitleTopMargin2 = (LinearLayout)findViewById(R.id.BarTitleTopMargin2);
        barTitleTopMargin3 = (LinearLayout)findViewById(R.id.BarTitleTopMargin3);
        barTitleTopMargin4 = (LinearLayout)findViewById(R.id.BarTitleTopMargin4);
        noData = (LinearLayout)findViewById(R.id.NoDataMask);
        previousButton = (Button)findViewById(R.id.PreviousDayButton);
        todayButton = (Button)findViewById(R.id.TodayButton);
        nextButton = (Button)findViewById(R.id.NextDayButton);
        
        telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
        
        // get previous day's leaderboard when previous button is clicked
        previousButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { getLeaderboardForTime(SocioUtils.previousDayFromTime(displayDateTime)); }});
        
        // get next day's leaderboard when next button is clicked
        nextButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { getLeaderboardForTime(SocioUtils.nextDayFromTime(displayDateTime)); }});
        
        // get today's leaderboard when today button is clicked
        todayButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { getLeaderboardForTime(SocioUtils.getTodayTime()); }});
        
        // re-create saved state
	    if(savedInstanceState != null) {
	    	displayDateTime = savedInstanceState.getLong("displayDateTime");
	    	int displayListCount = savedInstanceState.getInt("displayListCount");
	    	List<ClientUser> users = new ArrayList<ClientUser>();
	    	for(int userIndex=0; userIndex<displayListCount; userIndex++)
	    		users.add((ClientUser)savedInstanceState.getSerializable("user"+ userIndex));
	    	displayLeaderboard(users, false);
	    } else {
	    	getLeaderboardForTime(SocioUtils.getTodayTime());
	    }
        
    }
    
    /**
     * Gets all time leaderboard
     */
    private void getAllTime() {
    	showDialog(SEARCH_PROGRESS_DIALOG);
    	displayDateTime = -1;
    	
    	// params for http call
    	String udid = telephonyManager.getDeviceId();
        Hashtable<String,Object> extraParams = new Hashtable<String, Object>();
        Uri.Builder uriBuilder = new Uri.Builder();
		uriBuilder = uriBuilder.encodedPath(getResources().getString(R.string.socio_prod_host) + "resources/allTime/leaderboard").
		appendQueryParameter("udid", udid);
		extraParams.put("uriBuilder", uriBuilder);
		BackendThread thread = new BackendThread(handler, BackendThreadModes.GetLeaderboard, extraParams);
		thread.start();
    }
    
    /**
     * Gets leaderboard for a specific day
     * @param time Time representing the day
     */
    private void getLeaderboardForTime(long time) {
    	showDialog(SEARCH_PROGRESS_DIALOG);
    	displayDateTime = time;
    	
    	// params for http call
    	String udid = telephonyManager.getDeviceId();
        Hashtable<String,Object> extraParams = new Hashtable<String, Object>();
        Uri.Builder uriBuilder = new Uri.Builder();
		uriBuilder = uriBuilder.encodedPath(getResources().getString(R.string.socio_prod_host) + "resources/day/leaderboard").
		appendQueryParameter("dayTime", ""+time).appendQueryParameter("udid", udid);
		extraParams.put("uriBuilder", uriBuilder);
		BackendThread thread = new BackendThread(handler, BackendThreadModes.GetLeaderboard, extraParams);
		thread.start();
    }
    
    /**
	 * Handle message return from threads
	 * @param msg Message returned from thread
	 */
	@SuppressWarnings("unchecked")
	private void handleBackendThreadMessage(Message msg) {
		switch((BackendThreadMessages)msg.getData().getSerializable("message type")) {
		case SearchSuccessful:
			displayLeaderboard((List<ClientUser>)msg.obj, true);
			break;
		case TroubleGettingLeaderboard:
			displayLeaderboard(new ArrayList<ClientUser>(), true);
			showDialog(TROUBLE_GETTING_LEADERBOARD);
			break;
		case NoDataFound:
			displayLeaderboard(new ArrayList<ClientUser>(), true);
			break;
		}
	}
	
	/**
	 * Displays leaderboard based on user quick scores
	 * @param users Users to graph
	 * @param isSearchDialogUp Indicates if a the search dialog was called before this method
	 */
	private void displayLeaderboard(List<ClientUser> users, boolean isSearchDialogUp) {
		displayList = users;
		
		boolean isScoring = true;
		
		boolean isAllTimeLeaderboard = false;
		if(displayDateTime == -1)
			isAllTimeLeaderboard = true;
		
		// set bar displays to invisible just in case we don't use them all
		barDisplay1.setVisibility(View.INVISIBLE);
		barDisplay2.setVisibility(View.INVISIBLE);
		barDisplay3.setVisibility(View.INVISIBLE);
		barDisplay4.setVisibility(View.INVISIBLE);
		
		// change buttons accordingly
		if(isAllTimeLeaderboard) {
			todayButton.setVisibility(View.VISIBLE);
    		nextButton.setVisibility(View.GONE);
    		previousButton.setVisibility(View.GONE);
		} else {
			if(displayDateTime < SocioUtils.getTodayTime()) {
	    		todayButton.setVisibility(View.VISIBLE);
	    		nextButton.setVisibility(View.VISIBLE);
	    	} else {
	    		todayButton.setVisibility(View.GONE);
	    		nextButton.setVisibility(View.GONE);
	    	}
	    	previousButton.setVisibility(View.VISIBLE);
		}
		
		// set date
    	if(isAllTimeLeaderboard)
    		graphDate.setText("All Time");
    	else
    		graphDate.setText(SocioUtils.dayTimeToString(displayDateTime));
		
		// if users empty set no data to be visible
		if(users.size() == 0)
			noData.setVisibility(View.VISIBLE);
		else
			noData.setVisibility(View.GONE);
		
		// graph up to 4 users' scores
		for(int userIndex=0; userIndex<users.size(); userIndex++) {
			ClientUser user = users.get(userIndex);
			
			boolean isUserOfPhone = false;
			// do special stuff for user of phone
			if(user.getUdid().length() > 0) {
				isUserOfPhone = true;
				if(!user.isScoring())
					isScoring = false;
			}
			
			// get bar index based on user index
			LinearLayout bar = null;
			LinearLayout barMask = null;
			RelativeLayout barDisplay = null;
			TextView barTitleNickname = null;
			TextView barTitlePoints = null;
			LinearLayout titleTopMargin = null;
			int barColor = 0;
			switch(userIndex) {
			case 0:
				bar = bar1;
				barMask = barMask1;
				barDisplay = barDisplay1;
				barTitleNickname = barTitleNickname1;
				barTitlePoints = barTitlePoints1;
				titleTopMargin = barTitleTopMargin1;
				barColor = Color.rgb(0, 0, 255);
				break;
			case 1:
				bar = bar2;
				barMask = barMask2;
				barDisplay = barDisplay2;
				barTitleNickname = barTitleNickname2;
				barTitlePoints = barTitlePoints2;
				titleTopMargin = barTitleTopMargin2;
				barColor = Color.rgb(0, 0, 213);
				break;
			case 2:
				bar = bar3;
				barMask = barMask3;
				barDisplay = barDisplay3;
				barTitleNickname = barTitleNickname3;
				barTitlePoints = barTitlePoints3;
				titleTopMargin = barTitleTopMargin3;
				barColor = Color.rgb(0, 0, 170);
				break;
			case 3:
				bar = bar4;
				barMask = barMask4;
				barDisplay = barDisplay4;
				barTitleNickname = barTitleNickname4;
				barTitlePoints = barTitlePoints4;
				titleTopMargin = barTitleTopMargin4;
				barColor = Color.rgb(0, 0, 128);
				break;
			}
			
			// if phone's user make bar red
			if(isUserOfPhone)
				bar.setBackgroundColor(Color.rgb(255, 0, 0));
			else
				bar.setBackgroundColor(barColor);
			
			// set bar mask weight to (1 - (user's pts percentage of top spot))
			// sdd .075 for the title top margin
			LinearLayout.LayoutParams barMaskParams = (LinearLayout.LayoutParams)barMask.getLayoutParams();
			LinearLayout.LayoutParams titleMarginParams = (LinearLayout.LayoutParams)titleTopMargin.getLayoutParams();
			if(userIndex == 0) {
				barMaskParams.weight = 0;
				titleMarginParams.weight = 0;
			} else {
				float percentage = (float)user.getQuickScore() / (float)users.get(0).getQuickScore();
				barMaskParams.weight = 1 - percentage;
				if(percentage >= .075)
					titleMarginParams.weight = (float)(1 - percentage + .075);
				else
					titleMarginParams.weight = 1 - percentage;
			}
			barMask.setLayoutParams(barMaskParams);
			titleTopMargin.setLayoutParams(titleMarginParams);
			
			// set bar title nickname and points
			// if user of phone bold "You"
			String nickname = user.getNickname();
			if(nickname.length() == 0)
				nickname = "No Nick";
			if(isUserOfPhone) {
				nickname = "You";
				barTitleNickname.setTextSize(20);
				barTitleNickname.setTypeface(Typeface.DEFAULT_BOLD);
			} else {
				barTitleNickname.setTextSize(15);
				barTitleNickname.setTypeface(Typeface.DEFAULT);
			}
			barTitleNickname.setText(nickname);
			barTitlePoints.setText("("+ user.getQuickScore() +" pts)");
			
			// set bar display visible
			barDisplay.setVisibility(View.VISIBLE);
		}
		
		if(isSearchDialogUp)
			dismissDialog(SEARCH_PROGRESS_DIALOG);
		
		if(!isScoring)
			showDialog(N0_SCORING_DIALOG);
	}
	
	/**
	 * Creates dialogs
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog = null;
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		switch (id) {
		case SEARCH_PROGRESS_DIALOG:
			ProgressDialog progressDialog = new ProgressDialog(this);
			progressDialog.setMessage("Getting scoring leaders. Please wait...");
			progressDialog.setCancelable(false);
			dialog = progressDialog;
			break;
		case NO_DATA_FOUND:
			// build alert dialog with error message and ok button
			builder.setMessage("No data found for the selected day.")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(NO_DATA_FOUND);
		           }
		       });
			dialog = builder.create();
			break;
		case TROUBLE_GETTING_LEADERBOARD:
			// build alert dialog with error message and ok button
			builder.setMessage("Trouble getting scoring leaders. Please try again")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(TROUBLE_GETTING_LEADERBOARD);
		           }
		       });
			dialog = builder.create();
			break;
		case N0_SCORING_DIALOG:
			// build alert dialog with error message and ok button
			builder.setMessage("You haven't enabled yourself to start earning points yet. Go to Settings" +
					" to begin earning points today.")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(N0_SCORING_DIALOG);
		           }
		       }).setPositiveButton("Settings", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(N0_SCORING_DIALOG);
		        	   Intent socioSettings = new Intent(SocioLauncher.this, SocioSettings.class);
		        	   startActivity(socioSettings);
		           }
		       });
			dialog = builder.create();
			break;
		}

		return dialog;
	}
	
	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.input_menu, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
        case R.id.AllTimeMenuItem:
        	getAllTime();
            return true;
        case R.id.SettingsMenuItem:
        	Intent socioSettings = new Intent(this, SocioSettings.class);
        	startActivity(socioSettings);
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }
    
    @Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		
		outState.putLong("displayDateTime", displayDateTime);
		outState.putInt("displayListCount", displayList.size());
		for(int userIndex=0; userIndex<displayList.size(); userIndex++)
			outState.putSerializable("user"+ userIndex, displayList.get(userIndex));
	}
}